package main

import (
	"context"
	"fmt"
	"go.etcd.io/etcd/clientv3"
	"log"
	"time"
)

const WxAccountsConfigStorePrefix = "root/config/custom/go_center_pay_strategy/wxconfig_store"
const ReceiptSymbolConfigStorePrefix = "root/config/custom/go_center_pay_strategy/receiptSymbol_store"
const MchConfigStorePrefix = "root/config/custom/go_center_pay_strategy/mch_store"
const BusinessConfigStorePrefix = "root/config/custom/go_center_pay_strategy/config_store"

const confPath = ReceiptSymbolConfigStorePrefix+"/2021"
//const confPath = "root/config/custom/go_center_pay_strategy/wxconfig_store/20201223184012"

func main() {
	cli, err := clientv3.New(clientv3.Config{
		//Endpoints:   []string{"10.25.232.131:2379"},
		Endpoints:   []string{"test-etcd-inner.qschou.com:2379"},
		DialTimeout: 10 * time.Second,
	})
	if err != nil {
		fmt.Printf("connect to etcd failed, err:%v\n", err)
		return
	}
	fmt.Println("connect to etcd success")
	defer cli.Close()

	readPathConf(cli)

	// 测试发现，删除key时，watch是监听不到的
	delPathConfWithPrefix(cli)

	//delPathConfForeach(cli)

	//DoBasic(cli, err)
	//DoLease(cli, err)
	//go DoKeepAlive(cli, err)

	// watch会阻塞当前进程，所以需要使用协程
	//go DoWatch(cli, err)
	//getQsc(err, cli)
	//go DoQsc(cli, err)
}

func readPathConf(cli *clientv3.Client) {
	fmt.Println(">>>read start>>>", confPath)

	bs, _ := cli.Get(context.TODO(), confPath, clientv3.WithPrefix())
	fmt.Println("read len(kvs)", len(bs.Kvs))
	for index, kv := range bs.Kvs {
		fmt.Printf("read index:%d,k:%v \n ", index, string(kv.Key))
	}

	fmt.Println("<<<read end<<<")
}

func delPathConfWithPrefix(cli *clientv3.Client) {
	fmt.Println(">>>del end>>", confPath)
	//del, _ := cli.Delete(context.TODO(), confPath, clientv3.WithPrefix())
	del, _ := cli.Delete(context.TODO(), confPath)
	fmt.Println(del)
	fmt.Println("<<<del end<<<")
}

func delPathConfForeach(cli *clientv3.Client) {
	fmt.Println(">>>del start>>>",confPath)
	paths, err := cli.Get(context.TODO(), confPath, clientv3.WithPrefix())
	if nil != err {
		fmt.Println(err)
	}
	for index, kv := range paths.Kvs {
		key := string(kv.Key)
		fmt.Printf("del index:%d,k:%v \n ", index, key)
		cli.Delete(context.TODO(), key)
	}
	fmt.Println("<<<del end<<<")
}



func getQsc(err error, cli *clientv3.Client) {
	//TODO  此处获取的配置，在etcd控制台看不到？WHY?
	get, err := cli.Get(context.TODO(), "/root/watch/config_store/20201201184414")
	if nil != err {
		log.Fatal(err)
	}
	fmt.Println(get)
}

//func DoQsc(cli *clientv3.Client, err error) {
//
//	wc := cli.Watch(context.TODO(), "/root/config_store", clientv3.WithPrefix())
//
//	for v := range wc {
//		for _, e := range v.Events {
//			fmt.Printf("type:%v k:%v  v:%v \n ", e.Type, string(e.Kv.Key), string(e.Kv.Value))
//			tmp := make(map[string]*Business)
//			err := json.Unmarshal(e.Kv.Value, &tmp)
//			if nil != err {
//				log.Fatal("business config update", "unmarshal err", "error", err)
//			}
//			for i, v := range tmp {
//				Businesses.Set(i, v)
//			}
//			tmp1, _ := json.Marshal(Businesses)
//			fmt.Println(string(tmp1))
//
//			// todo 此处etch 不落盘？
//			_, err = cli.Put(context.TODO(), BusinessConfigStorePrefix+"/"+time.Now().Format("20060102150405"), string(tmp1))
//			if nil != err {
//				err = errors.Wrap(err, "存放到etcd失败")
//			}
//		}
//	}
//
//}


// 续约
func DoKeepAlive(cli *clientv3.Client, err error) {
	resp, err := cli.Grant(context.TODO(), 10)
	if err != nil {
		log.Fatal(err)
	}

	_, err = cli.Put(context.TODO(), "/root/lease002", "lease002", clientv3.WithLease(resp.ID))
	if err != nil {
		log.Fatal(err)
	}

	// the key 'foo' will be kept forever
	ch, kaerr := cli.KeepAlive(context.TODO(), resp.ID)
	if kaerr != nil {
		log.Fatal(kaerr)
	}
	for {
		ka := <-ch
		fmt.Println("ttl:", ka.TTL)
	}
}

// 设置租约
func DoLease(cli *clientv3.Client, err error) {
	// 创建一个60s的续约
	grant, err := cli.Grant(context.TODO(), 60)
	if err != nil {
		log.Fatal(err)
	}
	// 60s之后，/root/lease001这个key就会被移除
	_, err = cli.Put(context.TODO(), "/root/lease001", "dead after 60s", clientv3.WithLease(grant.ID))
	if err != nil {
		log.Fatal(err)
	}

}

func DoWatch(cli *clientv3.Client, err error) {
	watch := cli.Watch(context.Background(), "/testdir/", clientv3.WithPrefix())
	for wresp := range watch {
		for _, ev := range wresp.Events {
			fmt.Printf("Type:%s key:%s Value:%s\n", ev.Type, ev.Kv.Key, ev.Kv.Value)
		}
	}
}
//
//func DoBasic(cli *clientv3.Client, err error) {
//	// put
//	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
//	_, err = cli.Put(ctx, "/testdir/test001", "dsb")
//	cancel()
//	if err != nil {
//		fmt.Printf("put to etcd failed, err:%v\n", err)
//		return
//	}
//	// get
//	ctx, cancel = context.WithTimeout(context.Background(), time.Second)
//	resp, err := cli.Get(ctx, "/root/test", clientv3.WithPrefix())
//
//	cancel()
//	if err != nil {
//		fmt.Printf("get from etcd failed, err:%v\n", err)
//		return
//	}
//	var result map[string]string = make(map[string]string)
//	for _, ev := range resp.Kvs {
//		fmt.Printf("%s:%s\n", ev.Key, ev.Value)
//		result[string(ev.Key)] = string(ev.Value)
//	}
//
//	for k, v := range result {
//		Businesses.Value[k] = &Business{}
//		BusinessSymbolMap[k] = struct{}{}
//		err := json.Unmarshal([]byte(v), Businesses.Value[k])
//		if nil != err {
//			panic(err)
//		}
//		fmt.Println("key", k, "value", v)
//
//	}
//}

//func (b *businesses) Set(key string, business *Business) {
//	b.rWLock.Lock()
//	defer b.rWLock.Unlock()
//	b.Value[key] = business
//}
